/**
 * strictc - the Strict compiler
 * Copyright (C) 2008 David Olsson (vonolsson@gmail.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <cstdlib>
#include <iostream>
#include <string>

#include "StrictLexer.h"
#include "StrictParser.h"

using namespace std;

static const string STRICTC_VERSION = "0.0.2-dev";

enum OptionHandlerResult {OHR_OK, OHR_OKANDEXIT, OHR_FAILURE};

typedef OptionHandlerResult (*OptionHandler)(int argc, char *argv[], int index);

struct Option {
    const char * const option;
    const char * const description;
    OptionHandler handler;
};

static OptionHandlerResult handleHelpOption(int argc, char *argv[], int index);
static OptionHandlerResult handleVersionOption(int argc, char *argv[], int index);

// Please keep this list sorted alphabetically on the option name!
static const Option options[] = {
    {"--help", "\t\tdisplay this help information and exit", handleHelpOption},
    {"--version", "\tdisplay version information and exit", handleVersionOption},
    {"", "", 0}
};

OptionHandlerResult handleHelpOption(int, char *argv[], int) {
    cout << "strictc - the Strict compiler, copyright (C) 2008 David Olsson" << endl
         << "strictc comes with ABSOLUTELY NO WARRANTY; see the LICENSE.txt file or" << endl
         << "http://www.gnu.org/licenses/gpl-2.0.html for details" << endl
         << endl
         << "usage: " << argv[0] << " [option(s)] [source-file ...]" << endl
         << "where option(s) is one or more of" << endl;
    for(int i = 0; options[i].handler != 0; i++) {
        cout << "\t" << options[i].option << options[i].description << endl;
    }
    
    return(OHR_OKANDEXIT);
}

OptionHandlerResult handleVersionOption(int, char **, int) {
    cout << "strictc version " << STRICTC_VERSION << endl;
    return(OHR_OKANDEXIT);
}

int main(int argc, char *argv[]) {
    int firstSource = 1;
    bool foundOption = false;
    for(int i = 1; i < argc; i++) {
        // Try and match this option against a known option in the option table.
        for(int j = 0; options[j].handler != 0; j++) {
            if(argv[i] == string(options[j].option)) {
                foundOption = true;
                switch(options[j].handler(argc, argv, i)) {
                    case OHR_OK:
                        break;
                    case OHR_OKANDEXIT:
                        return(EXIT_SUCCESS);
                    case OHR_FAILURE:
                        return(EXIT_FAILURE);
                }
                if(foundOption) {
                    break;
                }
            }
        }
        if(!foundOption) {
            // Assume this is the first source file name.
            firstSource = i;
            break;
        }
    }

    if (firstSource < argc) {
        // Loop through all given source files and try to compile them.
        for(int i = firstSource; i < argc; i++) {
            ANTLR3_INPUT_STREAM *input = antlr3AsciiFileStreamNew(reinterpret_cast<ANTLR3_UINT8 *>(argv[i]));
            if(input != 0) {
                StrictLexer *lexer = StrictLexerNew(input);

                ANTLR3_COMMON_TOKEN_STREAM *tokens = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lexer));
                StrictParser *parser = StrictParserNew(tokens);

                parser->sourceFile(parser);

                parser->free(parser);
                tokens->free(tokens);
                lexer->free(lexer);
                input->close(input);
            }
            else {
                cerr << argv[0] << ": could not open file " << argv[i] << "!" << endl;
                
                return(EXIT_FAILURE);
            }
        }
        
        return(EXIT_SUCCESS);
    }
    else {
        // No source files given!
        cerr << argv[0] << ": no input files (use the --help option for more information)!" << endl;
        
        return(EXIT_FAILURE);
    }
}
